/**
 * Created by ${PRODUCT_NAME}.
 * User: skylerparr
 * Date: 12/26/10
 * Time: 3:39 PM
 * To change this template use File | Settings | File Templates.
 */
package com.thoughtorigin.asset {
import com.thoughtorigin.loader.AbstractLoader;

import flash.display.DisplayObject;
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.events.SecurityErrorEvent;
import flash.utils.Dictionary;
import flash.utils.setTimeout;

public class CacheAssetManager implements AssetManager {

    private var _assetCache: AssetCache;
    private var _loadingDict: Dictionary;

    public function CacheAssetManager() {
        init();
    }

    protected function init(): void {
        _loadingDict = new Dictionary(true);
    }

    public function loadAsset(loader:AbstractLoader, successFunc:Function, failFunc:Function = null):void {
        if(_assetCache) {
            if(_assetCache.isAssetCached(loader.url)) {
                _assetCache.getAsset(loader.url, function(disp: DisplayObject): void {
                    successFunc.call(this, disp);
                });
                return;
            }
        }

        if(_loadingDict[loader.url]) {
            addToLoadingList(loader, successFunc, failFunc);
            return;
        }
        addListeners(loader);
        _loadingDict[loader.url] = [new LoadingFunctions(successFunc, failFunc)];

        loader.start();
    }

    protected function addToLoadingList(loader: AbstractLoader, successFunc:Function, failFunc:Function = null): void {
        _loadingDict[loader.url].push(new LoadingFunctions(successFunc, failFunc));
    }

    private function onLoadComplete(e: Event): void {
        var absLoader: AbstractLoader = AbstractLoader(e.target);
        if(_assetCache && !_assetCache.isAssetCached(absLoader.url)) {
            _assetCache.cacheAsset(absLoader);
        }
        removeListeners(absLoader);
        for each(var lf: LoadingFunctions in _loadingDict[absLoader.url]) {
            handle(absLoader, lf.successFunc);
        }
        delete _loadingDict[absLoader.url];
    }

    private function onFail(e: Event): void {
        var absLoader: AbstractLoader = AbstractLoader(e.target);
        removeListeners(absLoader);
        for each(var lf: LoadingFunctions in _loadingDict[absLoader.url]) {
            if(lf.failFunc != null) {
                lf.failFunc.call(this, absLoader);
            }
        }
        delete _loadingDict[absLoader.url];
    }

    private function handle(absLoader: AbstractLoader, func: Function): void {
        if(_assetCache) {
            _assetCache.getAsset(absLoader.url, function(disp: DisplayObject): void {
                func.call(this, disp);
            });
            return;
        }
        if(func != null) {
            if(absLoader) {
                func.call(this, absLoader.content);
            }
        }
    }

    private function addListeners(absLoader: AbstractLoader): void {
        absLoader.addEventListener(Event.COMPLETE, onLoadComplete);
        absLoader.addEventListener(IOErrorEvent.NETWORK_ERROR, onFail);
        absLoader.addEventListener(IOErrorEvent.IO_ERROR, onFail);
        absLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onFail);
    }

    private function removeListeners(absLoader: AbstractLoader): void {
        absLoader.removeEventListener(Event.COMPLETE, onLoadComplete);
        absLoader.removeEventListener(IOErrorEvent.NETWORK_ERROR, onFail);
        absLoader.removeEventListener(IOErrorEvent.IO_ERROR, onFail);
        absLoader.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, onFail);
    }

    [Inject]
    public function set assetCache(value: AssetCache): void {
        _assetCache = value;
    }
}
}

import com.thoughtorigin.loader.AbstractLoader;

class LoadingFunctions {
    public var successFunc: Function;
    public var failFunc: Function;

    public function LoadingFunctions(success: Function, fail: Function) {
        successFunc = success;
        failFunc = fail;
    }
}